package com.wenjiang.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wenjiang.common.lang.Result;
import com.wenjiang.common.util.JWTUtil;
import com.wenjiang.common.util.Md5Utils;
import com.wenjiang.common.vo.AdminLoginSuccess;
import com.wenjiang.entity.MallAdminUser;
import com.wenjiang.entity.MallPermission;
import com.wenjiang.filter.LoginFilter;
import com.wenjiang.handler.MyAccessDeniedHandler;
import com.wenjiang.handler.MyAuthenticationEntryPoint;
import com.wenjiang.mapper.MallPermissionMapper;
import com.wenjiang.service.impl.AdminUserDetailsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import sun.security.provider.MD5;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

@Configuration
@Slf4j
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    AdminUserDetailsService adminUserDetailsService;

    @Autowired
    MallPermissionMapper mallPermissionMapper;

    @Autowired
    MyAuthenticationEntryPoint myAuthenticationEntryPoint;

    @Autowired
    MyAccessDeniedHandler  myAccessDeniedHandler;

    String[] urls= {"/login/login"};


    /**
     *  静态等资源过滤
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {

        super.configure(web);
    }


    /**
     * 配置 访问的url 所需要的权限
     * @param http
     * @throws Exception
     */

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //查询所有的权限
        List<MallPermission> mallPermissions = mallPermissionMapper.selectList(null);
        // 给所有的权限添加相应的关键字 需要关键字才能访问
        mallPermissions.forEach((item)->{
            try {
                http.authorizeRequests().antMatchers(item.getUrl()).hasAnyAuthority(item.getPermKey());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });



//        // 配置没有任何截路径 开放的接口
//        for(String url:urls){
//            http.authorizeRequests().antMatchers(url).permitAll();
//        }
        // 设置登陆表单的提交路径 loginProcessingUrl 配置接口登陆路径  loginPage 配置登陆页面
        http.authorizeRequests().antMatchers("/login/login").permitAll().and().formLogin().loginProcessingUrl("/login" +
                "/login");
        
        //

        // 其他路径需要认证后才能访问
        http.authorizeRequests().antMatchers("/**").fullyAuthenticated();

        // 如果springboot 已经做好了跨域 springsecurity 需要关闭跨域
        http.cors().and().csrf().disable();

        // 添加授权和认证 异常的处理器
        http.exceptionHandling().authenticationEntryPoint(myAuthenticationEntryPoint).accessDeniedHandler(myAccessDeniedHandler);

        //替换登陆的拦截器
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);


        


        super.configure(http);
    }

    /**
     * 配置 授权逻辑
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 重写 密码过滤器
        auth.userDetailsService(adminUserDetailsService).passwordEncoder(new PasswordEncoder() {
            // 获取数据库的密码
            @Override
            public String encode(CharSequence rawPassword) {
                log.info("encode方法的密码"+rawPassword);
                return (String) rawPassword;
            }

            // 对比
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                //
                log.info("对比密码:"+"登进来的密码"+rawPassword+"数据录获取的密码"+encodedPassword);

                return  Md5Utils.MD5Encode((String) rawPassword).equals(encodedPassword);
            }
        });
    }


    /**
     * 配置登陆的过滤器
     */

    @Bean
    LoginFilter loginFilter() throws Exception {
        LoginFilter loginFilter = new LoginFilter();
        loginFilter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                response.setContentType("application/json;charset=utf-8");
                PrintWriter out = response.getWriter();
                // 获取登陆成功的信息
//                Hr hr = (Hr) authentication.getPrincipal();
                //用户详细信息
                MallAdminUser principal =(MallAdminUser) authentication.getPrincipal();

                //构建返回参数 构建token
                String token = JWTUtil.createToken(principal.getUserId());

                AdminLoginSuccess adminLoginSuccess= new AdminLoginSuccess();
                adminLoginSuccess.setToken(token);


//                hr.setPassword(null);
//                RespBean ok = RespBean.ok("登录成功!", hr);
                String s = new ObjectMapper().writeValueAsString(Result.succ(adminLoginSuccess,"登陆成功"));

                HttpSession session = request.getSession();
                //存入登陆成功的用户名
                session.setAttribute("userName", principal.getUsername());

                out.write(s);
                out.flush();
                out.close();
            }
        });
        loginFilter.setAuthenticationFailureHandler(new AuthenticationFailureHandler() {
            @Override
            public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
                // 打印错误
                exception.printStackTrace();
                response.setContentType("application/json;charset=utf-8");
                PrintWriter out = response.getWriter();
                // 登陆失败后放回的结果
//                RespBean respBean = RespBean.error(exception.getMessage());
//                if (exception instanceof LockedException) {
//                    respBean.setMsg("账户被锁定，请联系管理员!");
//                } else if (exception instanceof CredentialsExpiredException) {
//                    respBean.setMsg("密码过期，请联系管理员!");
//                } else if (exception instanceof AccountExpiredException) {
//                    respBean.setMsg("账户过期，请联系管理员!");
//                } else if (exception instanceof DisabledException) {
//                    respBean.setMsg("账户被禁用，请联系管理员!");
//                } else if (exception instanceof BadCredentialsException) {
//                    respBean.setMsg("用户名或者密码输入错误，请重新输入!");
//                }
                out.write(new ObjectMapper().writeValueAsString(Result.fail("登陆失败")));
                out.flush();
                out.close();
            }
        });
        loginFilter.setAuthenticationManager(authenticationManagerBean());
        // 设置拦截的路径
        loginFilter.setFilterProcessesUrl("/login/login");
        return loginFilter;
    }
}
